import { storage, uploadFile, Promisify, setTitle } from './wxapi'
import moment from '../lib/moment'

/**
 * 把对象转化成字符串参数或把value，key转化成字符串参数
 * @param {Object,any} param [参数对象或值]
 * @param {String} key [参数名]
 */
const parseParam = (param, key) => {
	var paramStr = ''
	if (
		typeof param == 'string' ||
		typeof param == 'number' ||
		typeof param == 'boolean'
	) {
		paramStr += '&' + key + '=' + encodeURIComponent(param)
	} else {
		Object.keys(param).map(i => {
			var k =
				key == null
					? i
					: key + (param instanceof Array ? '[' + i + ']' : '.' + i)
			paramStr += '&' + parseParam(param[i], k)
		})
	}
	return paramStr.substr(1)
}

// 注入数据
const injectDepend = inject => {
	if (!inject) {
		return Promise.resolve(null)
	}
	return Promise.all(Object.keys(inject).map(key => inject[key].call())).then(
		dataSet => {
			let injectData = {}
			Object.keys(inject).map((key, index) => {
				injectData[key] = dataSet[index]
			})
			return injectData
		}
	)
}
/**
 * 发请求
 * @param {String} endpoint [地址]
 * @param {Object} opt [参数对象]
 */
const CallApi = (endpoint, opt = {}) => {
	const ext = wx.getExtConfigSync()
	const fullUrl =
		endpoint.indexOf(ext.api_root) === -1
			? ext.api_root + '/api/web' + endpoint
			: endpoint
	opt.url = fullUrl
	opt.method = opt.method || 'GET'
	if (opt.method == 'GET' && opt.data) {
		opt.url += '?' + parseParam(opt.data)
		opt.data = {}
	}
	opt.header = Object.assign(
		{},
		{
			AgentId: ext.agent_id,
			Token: wx.getStorageSync('token'),
			Scene: wx.getStorageSync('scene'),
			From: opt.from_tag || ext.from_tag
		},
		opt.header || {}
	)
	return Promisify(wx.request)(opt)
		.then(res => {
			return res.data
		})
		.then(data => {
			if (data.code == 'SUCCESS') {
				return data
			}
			return Promise.reject(data)
		})
}
const uploadFiles = (files, params) =>
	Promise.all(files.map(file => uploadFile(file, params)))

/**
 * 解析场景参数
 * @param {String} scene 场景
 */
const parseSceneParams = scene => {
	let params = {}
	let paramsArr = scene.split('&')
	paramsArr.forEach(param => {
		let paramArr = param.split('=')
		params[paramArr[0]] = paramArr[1]
	})
	return params
}

/**
 * 判断网络类型
 */
const checkNetwork = () => {
	return Promisify(wx.getNetworkType)().then(res => {
		return res.networkType
	})
}

/**
 * 获取本地文件
 * @param {String} value 地址
 */
const localFile = value => {
	const arr = /(http|https):\/\/(file|file2).duduapp.net\/(.*)/.exec(value)
	return `/${arr[2]}/${arr[3]}`
}

/**
 * 参数对象转字符串 serialize()
 * @param { Object } options  参数
 * @param { deleteAnd } deleteAnd  是否删除 第一个&
 * @param { deleteId } deleteId  是否删除id
 */
const serializeOptions = (options, deleteAnd = true, deleteId = false) => {
	if (deleteId) {
		delete options.id
	}
	let serializeOptions = ''
	for (const key in options) {
		serializeOptions += `&${key}=${options[key]}`
	}
	if (serializeOptions.length > 0 && deleteAnd) {
		serializeOptions = serializeOptions.slice(1)
	}
	return serializeOptions
}

// 检查错误并设置错误
const checkError = function(err) {
	// 加载数据超时
	if (
		err.errMsg === 'request:fail timeout' ||
		err.errMsg === 'request:fail 请求超时。'
	) {
		this.setData({
			hasLoaded: true,
			errorParams: {
				type: 104,
				title: '请求超时',
				msg: '加载数据超时了'
			},
			hasError: true
		})
	} else if (err.code == 'FAIL') {
		this.setData({
			hasLoaded: true,
			errorParams: {
				type: 105,
				title: '出错了',
				msg: err.msg
			},
			hasError: true
		})
	} else {
		this.setData({
			hasLoaded: true,
			errorParams: {
				type: 106,
				title: '出错了',
				msg: '页面出错了'
			},
			hasError: true
		})
	}
}

const GetApi = (endpoint, params = {}, opt = {}) =>
	CallApi(
		endpoint,
		Object.assign({}, opt, {
			data: params
		})
	)
const PostApi = (endpoint, params = {}, opt = {}) =>
	CallApi(
		endpoint,
		Object.assign({}, opt, {
			data: params,
			method: 'POST'
		})
	)
const PutApi = (endpoint, params = {}, opt = {}) =>
	CallApi(
		endpoint,
		Object.assign({}, opt, {
			data: params,
			method: 'PUT'
		})
	)
const DeleteApi = (endpoint, params = {}, opt = {}) =>
	CallApi(
		endpoint,
		Object.assign({}, opt, {
			data: params,
			method: 'DELETE'
		})
	)

/**
 * 跳转错误页面 *
 * @param { String } type  错误类型
 * @param { String } title  标题
 * @param { String } msg 错误详情
 * @returns
 */
const goError = (type, title, msg) => {
	return Promisify(wx.redirectTo)({
		url: `/pages/error/index?type=${type}&title=${title}&msg=${msg}`
	})
}
module.exports = {
	Promisify, //  Promise简化回调
	CallApi, // 调用接口
	GetApi, // 调用接口
	PostApi, // 调用接口
	PutApi, // 调用接口
	DeleteApi, // 调用接口
	moment, // 时间插件
	localFile, // 判断是否是本地文件
	checkNetwork, // 检查网络错误
	parseSceneParams, // 获取场景参数
	uploadFiles, //上传文件
	serializeOptions, // 串行化options参数
	goError, // 跳转错误页
	checkError, // 检查错误并设置错误
	initPage: opt =>
		Page(
			Object.assign({}, opt, {
				app: getApp(),
				onLoad(options) {
					// 检查网络
					checkNetwork()
						.then(networkType => {
							console.log(networkType)
							if (networkType === 'none') {
								// throw new Error('无网络')
								this.setData({
									hasLoaded: true,
									hasNetwork: false
								})
								setTitle('无网络')
							} else {
								console.log('网络类型: ', networkType)
								this.setData({
									hasLoaded: false,
									hasNetwork: true
								})
							}
							return networkType
						})
						.then(networkType => {
							// 没有网停止
							if (networkType === 'none') return

							//注入依赖到data
							return injectDepend(
								Object.assign(
									{},
									{
										config: this.app.getConfig.bind(
											this.app
										),
										userInfo: this.app.getUserInfo.bind(
											this.app
										)
									},
									opt.inject
								),
								this
							).then(injectData => {
								injectData && this.setData(injectData)
								opt.onLoad && opt.onLoad.bind(this, options)()

								// 把场景中参数转到options
								if (options.scene && options.scene.length > 0) {
									let scene = decodeURIComponent(
										options.scene
									)
									delete options.scene
									options = Object.assign(
										options,
										parseSceneParams(scene)
									)
								}
								const optionsStr = serializeOptions(options)
								// 设置参数对象
								this.setData({
									options,
									optionsStr
								})
							})
						})
				}
			})
		)
}
